﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using XboxOneDriver;
using vJoyInterfaceWrap;
using XboxOneDriverApp.Properties;
using System.Collections;

namespace XboxOneDriverApp
{
    public partial class XboxControl : UserControl, IDisposable
    {
        private XboxOneGamepad gamepad;
        private vJoy joystick;
        private vJoy.JoystickState iReport;
        private uint id;

        public XboxControl()    
        {
            InitializeComponent();

            
        }

        private void XboxControl_Load(object sender, EventArgs e)
        {
            gamepad = new XboxOneGamepad();
            gamepad.OnDataArrive += gamepad_OnDataArrive;
            gamepad.OnConnectedChanged += gamepad_OnConnectedChanged;
            gamepad_OnConnectedChanged(gamepad, gamepad.Connected);
        }
        void gamepad_OnConnectedChanged(XboxOneGamepad data, bool connected)
        {
            if (!connected && joystick != null)
            {
                DisableVJoy();
            }

            if (connected)
            {
                pictureBox1.Image = Resources.xbox_one_logo;
            }
            else
            {
                pictureBox1.Image = Resources.xbox_one_logo_dark;
            }
        }

        void gamepad_OnDataArrive(XboxOneGamepad data, XboxOneButtonData buttons)
        {
            if (joystick == null)
            {
                return;
            }

            iReport.bDevice = (byte)id;

            short max = short.MaxValue;
            ushort umax = ushort.MaxValue;
            short middle = short.MaxValue / 2;

            iReport.AxisX = buttons.stick_left_x + middle;
            iReport.AxisY = -buttons.stick_left_y + middle;
            iReport.AxisXRot = buttons.stick_right_x + middle;
            iReport.AxisYRot = -buttons.stick_right_y + middle;

            float leftTrigger = buttons.trigger_left / 2048.0f; // max = 1024
            float rightTrigger = buttons.trigger_right / 2048.0f; // max = 1024
            iReport.AxisZ = (int)(leftTrigger * umax);
            iReport.AxisZRot = (int)(rightTrigger * umax);

            int angle = 0;
            if (buttons.dpad_right)
            {
                if (buttons.dpad_up)
                {
                    angle += 45;
                }
                else if (buttons.dpad_down)
                {
                    angle += 135;
                }
                else
                {
                    angle += 90;
                }
            }
            else if (buttons.dpad_down)
            {
                if (buttons.dpad_left)
                {
                    angle += 225;
                }
                else
                {
                    angle += 180;
                }
            }
            else if (buttons.dpad_left)
            {
                if (buttons.dpad_up)
                {
                    angle += 315;
                }
                else
                {
                    angle += 270;
                }
            }

            if (!buttons.dpad_right && !buttons.dpad_up &&
                !buttons.dpad_left && !buttons.dpad_down)
            {
                iReport.bHats = 0xFFFFFFFF;
            }
            else
            {
                // multiply by 100
                iReport.bHats = (uint)(angle * 100);
            }

            bool triggerButton = false; //this.checkBox1.Checked;

            // Some bitwise magic:
            BitArray bit = new BitArray(new bool[]
                {
                    buttons.a,
                    buttons.b,
                    buttons.x,
                    buttons.y,
                    buttons.bumper_left,
                    buttons.bumper_right,
                    buttons.back,
                    buttons.start,
                    buttons.stick_left_click,
                    buttons.stick_right_click,
                    buttons.centerButton,
                    triggerButton ? buttons.trigger_left > 0.1f : false,
                    triggerButton ? buttons.trigger_right > 0.1f : false
                });
            int[] result = new int[1];
            bit.CopyTo(result, 0);
            iReport.Buttons = (uint)result[0];

            joystick.UpdateVJD(id, ref iReport);
        }

        private void button_Enable_Click(object sender, EventArgs e)
        {
            if (joystick == null)
            {
                if (!gamepad.Connected)
                {
                    MessageBox.Show("Gamepad not connected!");
                    return;
                }

                joystick = new vJoy();
                if (!joystick.vJoyEnabled())
                {
                    MessageBox.Show("VJoy not enabled!");
                    return;
                }

                //id = (uint)num_Vjoy.Value;
                VjdStat status = joystick.GetVJDStatus(id);

                // Acquire the target
                if ((status == VjdStat.VJD_STAT_OWN) || ((status == VjdStat.VJD_STAT_FREE) && (!joystick.AcquireVJD(id))))
                {
                    MessageBox.Show("Failed to acquire vJoy device number " + id);
                    return;
                }

                //button_Enable.Text = "Disable";
                joystick.ResetVJD(id);
            }
            else
            {
                DisableVJoy();
            }
        }

        private void DisableVJoy()
        {
            /*button_Enable.Invoke(new Action(() =>
            {
                button_Enable.Text = "Enable";
            }));*/

            // stop
            if (joystick != null)
            {
                joystick.RelinquishVJD(id);
                joystick = null;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (joystick != null)
            {
                joystick.SetBtn(gamepad.Data.a, id, 1); // keep updating so we dont lose track
            }

            // check if we are connected
            if (!gamepad.Connected)
            {
                gamepad.Connect();
            }
        }

        public void Dispose()
        {
            gamepad.Dispose(); // The order for disposing is INTENDED! Gamepad first!!
            DisableVJoy();
        }
    }
}
